home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / FORTH / FORTHMAC / OLD / DOCS / !Forthmacs.docs.ascii.tutorial < prev    next >
Encoding:
Text File  |  1996-06-15  |  29.8 KB  |  749 lines

  1.  
  2. Forth Tutorial
  3. **************
  4.  
  5.  
  6. This chapter is a brief tutorial about the Forth language.  It will 
  7. get you started with Forth, but you should probably buy a Forth book 
  8. to learn more.  
  9.  
  10. If you already know how to program in Forth, you may skip this 
  11. chapter.  You may want to look at the chapter "Glossary Functional 
  12. Index".  
  13.  
  14.  
  15. Forth is a complete programming language with some unique features.  
  16. In fact, it is probably unlike any other language you have ever used.  
  17. Please don't let it's "strangeness" cause you to immediately reject it 
  18. --- once you get used to it, you may find that you can use Forth to 
  19. write working programs faster than you ever dreamed possible.  
  20.  
  21. Forth is often described as an assembler, compiler, operating system, 
  22. editor, and command language all rolled into one.  In addition, most 
  23. of the Forth system is written in Forth.  
  24.  
  25. To find out more about your RISC OS Forthmacs system try 
  26.     words
  27.     see words
  28.     whatis words
  29. or others.  
  30.  
  31.  
  32. Getting Started
  33. ===============
  34.  
  35. If you sit down to a computer running Forth, you'll probably see the 
  36. word OK right before the cursor.  OK is the "prompt".  It means that 
  37. Forth is ready for you to type something.  Suppose you type 
  38.  
  39. 1 2 + .
  40.  
  41. Always type the cr, Return, lf, Linefeed, or whatever equivalent key 
  42. your terminal has, at the end of the line.  Forth will respond with 
  43.  
  44. 3
  45.  
  46. You have just added 1 and 2, and printed the result.  
  47.  
  48. I am going to assume at this point that you understand the concept of 
  49. a stack.  Forth uses stacks heavily.  In fact, the consistent stack 
  50. orientation is the key to Forth's ability to pack a lot of capability 
  51. in a small amount of memory.  
  52.  
  53. Going back to our example, typing "1" caused the number 1 to be pushed 
  54. onto Forth's main stack, which is called the data stack.  Typing "2" 
  55. caused the number 2 to be pushed onto the same stack, on top of the 1.  
  56. The "+" caused two numbers to be popped off the stack, in this case 1 
  57. and 2.  The numbers were added together and the result was put back on 
  58. the stack.  The "." caused a number to be popped off the stack, in 
  59. this case 3, and printed on the terminal.  
  60.  
  61. If you have an HP calculator, no doubt this sounds very familiar to 
  62. you.  An important differences is that HP calculators have a stack 
  63. that is 4 numbers deep, whereas Forth's stack is much larger, 
  64. typically more than 64 numbers.  In RISC OS Forthmacs this is PS-SIZE 
  65. divided by the cell size.  
  66.  
  67. Other arithmetic operators that Forth knows about are - (minus), * 
  68. (times), and / (divide), as well a some others that we'll worry about 
  69. later.  The arithmetic is performed as 32-bit integer arithmetic, 
  70. although there are operators which will cope with other kinds of 
  71. numbers.  
  72.  
  73.  
  74. Defining your own words
  75. =======================
  76.  
  77. A Forth system understands a number of "words", each of which causes 
  78. something to happen, usually to the stack.  In our example, "+" and 
  79. "." were both words.  You can define your own words in terms of words 
  80. the system already knows.  Once defined, your words may be used just 
  81. as though they they were system words.  Another example: 
  82.  
  83. : addprint   + .   ;
  84.  
  85. Here, the ":", which is a system word, causes a new word to be 
  86. defined, in this case addprint.  The definition of addprint is (B + .  
  87. ), which means that when you execute addprint, two numbers will be 
  88. taken from the stack and the sum printed.  The ;, another system word, 
  89. terminates the definition.  If you were to later type 
  90.  
  91. 23 45 addprint
  92.  
  93. Forth would respond with 
  94.  
  95. 68
  96.  
  97. A definition of this sort is called a "colon definition".  A 
  98. distinguishing characteristic is that the new word is defined in terms 
  99. of other Forth words.  It is also possible to define a word in terms 
  100. of the assembly language of the machine you are actually running on.  
  101. This kind of definition is called a "code definition", and is not used 
  102. nearly as often as colon definitions.  
  103.  
  104. If you wished to later use addprint in the definition of another word, 
  105. you could do so just as though addprint were a system-supplied word.  
  106.  
  107. : addprint2 addprint addprint ;
  108. 1 2 3 4  addprint2
  109.  
  110. would result in 
  111.  
  112. 7 3
  113.  
  114. Note the order in which the numbers were added.  The reason is that, 
  115. when addprint2 is executed, 4 is on top of the stack, with 3 
  116. underneath it.  The first addition will thus be 3+4.  
  117.  
  118. It is important to keep track of what is on the stack when you are 
  119. writing Forth programs.  An essential part of the documentation of a 
  120. Forth word is a stack diagram.  A stack diagram shows what the word 
  121. expects to be on the stack when it starts executing, and what it 
  122. leaves on the stack after it is finished.  The stack diagram for 
  123. addprint would be 
  124.  
  125. ( n1 n2 -- sum )
  126.  
  127. showing that two numbers ( n1 and n2 ) are expected to be on the stack 
  128. at the start, and that addprint leaves one number on the stack ( sum ) 
  129. when it is finished.  The "--" shows where the word executes, or, in 
  130. other words, it separates the input parameters from the output 
  131. parameters.  
  132.  
  133. Stack diagrams are enclosed in parentheses, because parentheses are 
  134. used in Forth to enclose comments.  The Forth system will ignore 
  135. everything between "(" and the next ")".  The space between "(" and 
  136. "n1" is necessary.  The space between "sum" and ")" is optional in 
  137. most Forth's, but it is a good idea to include it anyway.  
  138.  
  139. By convention, the rightmost number (n2) is the one that is on top of 
  140. the stack.  Thus ( a b c -- d e f ) would signify a word which 
  141. expected c on top of the stack, b under c, and a under b.  After 
  142. execution, f would be on top, with e under f, and d under e.  
  143.  
  144.  
  145. Variables, @, !
  146. ===============
  147.  
  148.  
  149. variable  john ( -- adr )
  150.  
  151. defines a variable called john and allocates one 32-bit machines word 
  152. for it.  The stack diagram shows that when john is executed, an 
  153. address will be left on the stack.  The address is the address of the 
  154. word that was allocated for john.  Right now we don't know what value 
  155. is contained in the variable, so let's put something in it.  
  156.  
  157. 123 john !
  158.  
  159. will put the number 123 in the variable.  ! , pronounced 'store' , is 
  160. the store operator.  Its stack diagram looks like ( value adr -- ), 
  161. meaning that it expects an address on the top of the stack and a value 
  162. underneath the address.  The value will be put in the machine word at 
  163. the indicated address, and both arguments will be removed from the 
  164. stack.  
  165.  
  166. Note in this example that the address was left by the word john.  It 
  167. is an important point that variables leave their addresses, rather 
  168. than their values.  If the value of a variable is needed, the @ 
  169. (fetch) operator is used.  
  170.  
  171. john @
  172.  
  173. will leave the value contained in the variable, in this case 123, on 
  174. the stack.  The stack diagram for @ is ( adr -- value ).  
  175.  
  176. It is reasonable to ask why it works this way, rather than having a 
  177. variable return its value.  In fact, a scheme to do this was discussed 
  178. in the Forth community for awhile, and the final consensus was that 
  179. the the consistency and regularity of the @ and ! operators was too 
  180. powerful to give up.  Forth is not the only language to do it is this 
  181. way.  BLISS is another language which requires an explicit operator to 
  182. return the value of a variable.  
  183.  
  184. Similar operators, C! and C@, are provided for storing and fetching 
  185. bytes instead of 32-bit quantities.  The stack only holds 32-bit 
  186. quantities, so the bytes are stored in the least-significant part of 
  187. the 32-bit number on the stack.  
  188.  
  189. w!  ( w adr -- )        stores the least-significant 16 bits of the number
  190.                         on the stack into the 16-bit memory location at addr
  191. w@  ( adr -- w )        fetches the 16-bit word at addr, leaving it on the
  192.                         stack.  The high-order bits of the stack item are
  193.                         zeroed.
  194. c!  ( byte adr -- )     stores the least-significant byte of the stack
  195.                         item into the 8-bit memory location at adr 
  196. c@  ( adr -- byte )     fetches the byte at addr
  197. +!  ( n adr -- )        adds n to the contents of the 32-bit word at addr
  198.  
  199.  
  200. Constants
  201. =========
  202.  
  203.  
  204. 32 constant buflen
  205.  
  206. defines a constant whose value is 32.  When buflen is executed, it 
  207. leaves its value, in contrast to a variable, which leaves its address.  
  208. There is no explicit mechanism provided for changing the value of a 
  209. constant.  Many Forth systems may be tricked into telling you the 
  210. address where the value of a constant is actually stored, so it may be 
  211. possible to change the value.  However, this is non-standard and 
  212. implementation dependent.  Use a variable if you want to change the 
  213. value.  
  214.  
  215. buflen buflen + .
  216.  
  217. results in 
  218.  
  219. 64
  220.  
  221. buflen john @ + .
  222.  
  223. results in 
  224.  
  225. 155
  226.  
  227. assuming that john was defined and initialised as before to 123.  you 
  228. should make sure you understand why the @ is needed after john but not 
  229. after buflen.  
  230.  
  231. The stack diagram for a constant is ( -- value ).  Remember that this 
  232. is what happens to the stack when the constant is executed, not when 
  233. it is defined.  
  234.  
  235. More generally, the word CONSTANT need not be explicitly preceded by a 
  236. number.  CONSTANT takes the initial value off of the stack.  The stack 
  237. diagram is 
  238.  
  239. constant  \ name  ( initial_value -- )
  240.  
  241. "\ name" means that when the defining word constant executes, it takes 
  242. a name ( a sequence of non-blank characters ) out of the input stream 
  243. and uses that name for something.  In this case, the name is used as 
  244. the name of the new constant.  Notice that distinction between 
  245. arguments that are taken from the stack and names that are taken from 
  246. the input stream ( the input stream is what you type at the terminal 
  247. ).  
  248.  
  249. Since typing a number puts that number on the stack, our example works 
  250. fine.  It is also possible to use Forth to calculate the value of the 
  251. constant, as in 
  252.  
  253. buflen 10 * constant bigbufsize
  254.  
  255. which defines a constant whose value is 10 times buflen, or 320.  This 
  256. is completely general; if you can get a number on the stack by any 
  257. means whatsoever, you can define a constant which returns that value.  
  258.  
  259.  
  260. Stack Manipulation
  261. ==================
  262.  
  263. The following words rearrange numbers on the stack.  
  264.  
  265. dup  ( n -- n n )   duplicates the number on top of the stack.  This is a
  266.                     real workhorse - dup is used a lot when you want to
  267.                     make a copy because you want to remember a number but
  268.                     the word you want to use next will "eat" it.
  269. drop  ( n -- )      discards the number on top of the stack.
  270. swap  ( n1 n2 -- n2 n1 )    exchanges the positions of the number on top
  271.                             of the stack and the number underneath it.  
  272.                             Suppose you had 3 4 on the stack and you
  273.                             wanted to compute 4-3.  You could do SWAP -
  274.                             and you would get what you wanted.
  275. over ( n1 n2 -- n1 n2 n1 )  copies the number which is directly
  276.                             underneath the top of the stack so that a copy
  277.                             of it on top.
  278. rot ( n1 n2 n3 -- n2 n3 n1 ) pulls the third stack element to the top
  279.                             and moves the two which were above it
  280.                             down to fill its vacancy.
  281. pick  (  np np-1 np-2 ... n0 p -- np np-1 np-2 np-2 ... n0 np )
  282.                       copies the p-th stack element to the top of the
  283.                       stack; 0 pick is equivalent to dup
  284.                              1 pick is equivalent to over
  285. roll  ( np np-1 np-2 ... n0 p -- np-1 np-2 ... n0 np )
  286.                       moves the p-th stack element to the top and moves
  287.                       the others down to fill the vacancy.  3 roll is
  288.                       equivalent to rot
  289. depth  ( -- n )       leaves the number of items that were on the stack
  290.                       before depth executed.  The number that depth leaves
  291.                       on the stack is not included in the count.
  292.  
  293.  
  294. Conditionals
  295. ============
  296.  
  297. Of course Forth lets you make tests and do different things based on 
  298. the results of those tests.  
  299.  
  300. Here are some words which are useful for comparisons.  
  301.  
  302. <     ( n1 n2 -- flag )   Flag is true if n1 < n2
  303. =     ( n1 n2 -- flag )   Flag is true if n1 = n2
  304. >     ( n1 n2 -- flag )   Flag is true if n1 > n2
  305. 0<    ( n1 -- flag )      Flag is true if n1 < 0
  306. 0=    ( n1 -- flag )      Flag is true if n1 = 0
  307. <>    ( n1 n2 --  flag )  Flag is true if n1 not equal to n2
  308. 0>    ( n1 -- flag )      Flag is true if n1 > 0
  309. u<    ( un1 un2 -- flag)  "<" for unsigned integers, such as addresses
  310. ?dup  (n-- [n] n )        duplicate the top of the stack only if it is not
  311.                           zero
  312.  
  313. The brackets mean that the number in brackets is present only if the 
  314. number on top of it is nonzero.  This convention is useful because 
  315. some words leave a flag on top of the stack to indicate whether or not 
  316. a particular operation succeeded.  If it did succeed, the flag is true 
  317. and the word has left some results on the stack underneath the flag.  
  318. If the operation failed, the flag is false (zero) and the results were 
  319. not put on the stack.  
  320.  
  321. The basic conditional in Forth is IF .  It's stack diagram is ( n -- 
  322. ), and it is used like: 
  323.  
  324. if  stuff_to_do_if_n_was_not_0  else  stuff_to_do_if_n_was_0  then
  325.  
  326. The ELSE part is optional.  The use of the English word "then" to 
  327. terminate the conditional is misleading, but that is the way it is.  
  328.  
  329. : absval  ( n -- absolute_value_of_n )  dup 0 < if 0 swap - then  ;
  330.  
  331. Let's analyze this definition carefully.  First of all, when this word 
  332. executes, it expects a number to be on top of the stack.  Call the 
  333. number n.  The first thing that happens is that DUP is executed, 
  334. putting another copy of n on top of the stack.  The stack now looks 
  335. like ( n n ).  Next we have "0", which puts a zero on top of the 
  336. stack, so that stack looks like ( n n 0 ).  Then we execute "<", which 
  337. compares to see whether or not n is less than 0.  The two numbers that 
  338. "<" compares are removed from the stack and a flag is left instead.  
  339.  
  340. Suppose that n was -5, so that n really was less than 0.  "<" would 
  341. then leave a -1 on top of the stack.  Any nonzero number is considered 
  342. to mean TRUE, whereas zero means FALSE. So the stack is ( n 1 ).  IF 
  343. takes the number off the top of the stack, sees that it is -1, and 
  344. proceeds to execute 0 SWAP - .  This has the effect of negating n.  
  345. The complete sequence of stack states is 
  346.  
  347. ( n )  dup  ( n n )  0  ( n n 0 )  <  ( n 1 )  if  ( n )
  348.  0  ( n 0 )  swap  ( 0 n )  -  ( -n )  then  ( -n )
  349.  
  350. The THEN terminates the conditional.  
  351.  
  352. If n had been positive, "<" would have left a zero, because 0 is not 
  353. greater than a positive number.  IF would have taken the zero off of 
  354. the stack and then skipped the stuff between IF and THEN. If there had 
  355. been an ELSE clause, it would have been executed.  
  356.  
  357. Instead of DUP 0 < , we could have used DUP 0< .  
  358.  
  359. As a matter of fact there is an easier way to negate a number than 
  360. 0 SWAP - .  You can just use NEGATE ( n -- n ).  In fact, absval 
  361. duplicates the function provided by system-supplied Forth word ABS ( n 
  362. -- |n| ).  
  363.  
  364. IF ...  ELSE ...  THEN may be nested to any depth, provided of course 
  365. that there is a THEN for every IF. IF may only be used within colon 
  366. definitions, which means that you can't just type in IF blah-blah-blah 
  367. THEN unless you are in the middle of defining some other word.  
  368.  
  369.  
  370. Loops
  371. =====
  372.  
  373. The basic looping construct is the DO LOOP. The stack diagram is 
  374. (end+1 start -- ).  Examples are necessary.  
  375.  
  376. : printlots ( n9 n8 ... n1 n0 -- ) 10 0 do . loop ;
  377.  
  378. will print ten numbers from off of the stack.  The loop will start at 
  379. 0 and end after 9.  
  380.  
  381. You can get at the loop index by using I .  It leaves the loop index 
  382. on the stack (where else?).  
  383.  
  384. : sumit010 ( -- sum ) 0 11 1 do i + loop ;
  385.  
  386. will add up the numbers from 1 to 10 inclusive.  The "0" is there 
  387. because the current running sum is kept on the stack, and the sum 
  388. needs to be initialised to 0.  
  389.  
  390. LOOP limits don't have to be positive.  Try out various limits and see 
  391. what happens.  
  392.  
  393. : bigjumps ( -- n ) 0   1000 0 do i +  10  +loop ;
  394.  
  395. will sum the multiples of 10 less than 1000.  +LOOP increments the 
  396. loop index by a number that it takes from the stack, in this case 10.  
  397. You can run loops backwards if you wish, by using +LOOP with a 
  398. negative increment.  
  399.  
  400. You may prematurely exit from a DO LOOP by executing LEAVE within the 
  401. loop.  You probably want to enclose the LEAVE in an IF ...  THEN 
  402. structure, because it doesn't make sense to construct a loop which 
  403. always exits after the first times through.  
  404.  
  405. More general loops may be constructed with 
  406.  
  407. begin ... until       or
  408. begin ... while ... repeat
  409.  
  410. In the case of BEGIN ...  UNTIL, the stack is checked by UNTIL. If if 
  411. is zero, looping continues at BEGIN. If it is one, execution continues 
  412. after UNTIL. 
  413.  
  414. For BEGIN ...  WHILE ...  REPEAT, WHILE checks the stack.  If it is 1, 
  415. looping proceeds, first executing the stuff between WHILE and REPEAT, 
  416. then starting over at BEGIN. If WHILE found a zero on the stack, the 
  417. stuff between WHILE and REPEAT is skipped and execution continues 
  418. after "repeat".  
  419.  
  420. Well, campers, it's example time again.  This time we'll assume that 
  421. there is a table somewhere in memory.  This table consists of 8-word 
  422. entries, and the end of the table is flagged by a -1 in the first word 
  423. of the last entry.  We would like to scan through the table and add a 
  424. number to the third word in each entry.  This third word represents 
  425. the age of an employee, so we'll call it AGE .  Our operation will 
  426. make everybody older.  Study this example carefully.  It shows how 
  427. Forth programs should be constructed with simple words.  
  428.  
  429. : age  ( entry_adr -- age_adr )  \ converts entry adr to age adr
  430.    12 +
  431. ;
  432. : addin  ( n adr -- n adr )  \ adds n to the number at adr
  433.    over over                   \ copy both n and adr
  434.    age +!                      \ increase age by n
  435. ;
  436. : more?  ( adr -- adr flag )  \ flag is false iff adr points to a -1
  437.    dup @ -1 <>
  438. ;
  439. : +entry  ( adr1 -- adr2 )  \ advances to the next entry
  440.    32 +
  441. ;
  442. : older  ( n adr -- )  \ adds n to each age in table at adr
  443.    begin  more?  while  addin +entry  repeat  drop drop
  444. ;
  445.  
  446.  
  447. Supposing that there is a word EMPLOYEES which returns the address of 
  448. such a table, we could make a everybody 100 years older by typing 
  449.  
  450. 100 employees older
  451.  
  452. Notice that I was careful to define each word before I used it inside 
  453. another word.  This is a requirement with typical Forth systems.  
  454. There is no "forward referencing", so everything must be defined 
  455. before it is used.  This may seem archaic, but in fact it is seldom 
  456. ever missed.  The payoff is great, in terms of reduced compiler 
  457. complexity and conceptual simplicity.  There are Forth 
  458. "cross-compiler" and "meta-compiler" programs which allow forward 
  459. references to varying degree, but they are generally used to build 
  460. entire Forth kernels from scratch.  
  461.  
  462. Now suppose we want to print out multiples of 2 until the user types a 
  463. key on his keyboard, at which time we want to stop.  There is a word 
  464. KEY? which returns true if the user has typed something since the last 
  465. time we checked, 0 otherwise.  
  466.  
  467. : mults-of-2  ( -- )  0  begin  dup . 2 +  key?  until  drop  ;
  468.  
  469. Of course, this could have been done as 
  470.  
  471. : mults-of-2  ( -- )  32766 0  do  i .  key?  if leave then  2 +loop  ;
  472.  
  473. but the real point here was to illustrate the BEGIN ...  UNTIL .  
  474.  
  475. key?  ( -- flag )      input and output
  476.                        flag is true if a key has been typed.
  477. key  ( -- char )       key waits until the user types a character, then
  478.                        returns the character
  479. emit  ( char -- )      emit displays the char on the terminal
  480. space  ( -- )          displays a space character.
  481. cr  ( -- )             displays a carriage return, line feed
  482. spaces  ( n -- )       displays n spaces
  483. type  ( adr n -- )     displays n characters, beginning at adr
  484. ." string of characters to display"
  485.                        here you actually have to type the
  486.                        double-quote characters.  The string starts 
  487.                        after the space following the first quote, 
  488.                        and continues up to but not including the 
  489.                        last quote.
  490. expect  ( adr n -- )   accepts n characters from the terminal,
  491.                        storing them at addr.  If a carriage return is
  492.                        typed before n characters have been
  493.                        accumulated, expect fills out the rest of the
  494.                        n locations with nulls
  495. -trailing  ( adr nl -- adr n2 )
  496.                        reduces the character count n1 so that
  497.                        trailing blanks are omitted 
  498. count  ( adr -- adr+1 n )
  499.                        converts a packed string to an address and
  500.                        character count
  501.  
  502. A word about COUNT is in order.  Forth stores strings as a length byte 
  503. followed by a number of characters.  The length byte contains the 
  504. number of characters in the string, not including the length byte.  
  505. COUNT takes the address of a packed string, which is the address of 
  506. its length byte, and returns the address of the actual characters in 
  507. the string, which is 1 more than the address of the length byte.  On 
  508. top of that, it returns the value of the length byte.  
  509.  
  510. Note that Forth addresses are byte addresses.  If you add 1 to a Forth 
  511. address, you get the next byte.  To get the next word, you have to add 
  512. 2.  
  513.  
  514. Normally, when you are typing Forth words for it to execute, they are 
  515. being stored in a buffer called the "terminal input buffer".  To 
  516. execute the next word, it first has to be fetched from the terminal 
  517. input buffer.  To do this, a word called WORD is executed.  WORD takes 
  518. the next word from the terminal input buffer and stores it as a packed 
  519. string, then returns the address of the packed string.  The boundary 
  520. between one word and the next is denoted by a space character.  
  521. Actually, WORD accepts an argument which tells it what to use as the 
  522. separator character.  Normally, space is used, but if you want to use 
  523. WORD yourself, you are free to chose your own delimiter.  
  524.  
  525. word  \ word  ( delimiter_char -- adr )
  526.                 accepts the next word, or sequence of characters not
  527.                 including the delimiter_char, from the input stream.
  528.                 Stores it as a packed string and returns its address
  529.                 (the address of the length byte).
  530.  
  531.  
  532. Numeric I/O
  533. ===========
  534.  
  535. We have already seen how to use "." Also, we have seen that numbers 
  536. may be put on the stack simply by typing the number.  More options are 
  537. available, such as accepting or typing hexadecimal numbers.  
  538.  
  539. base  ( -- adr )     a variable which contains the value of the current
  540.                      numeric input and output base.
  541. hex  ( -- )          sets base to 16 ( default when running stand alone )
  542. decimal  ( -- )      sets base to 10 ( the default when running under unix )
  543. .  ( n -- )          displays n according to the current BASE
  544. u.  ( u -- )         displays u as an unsigned number
  545. .r  ( n r -- )       displays n right-justified in a field of width r
  546. u.r  ( u r -- )      like ".r", but unsigned
  547. ?  ( adr -- )        displays the contents of the memory location at address
  548.                      adr. Equivalent to "@ ."
  549. .s  ( -- )           displays the entire stack contents without removing
  550.                      anything from the stack
  551.  
  552.  
  553. Note that executing BASE @ . is useless as a way to find out what the 
  554. current value of BASE is.  You will always get 10 as the answer 
  555. because whatever BASE is, it will be typed as "10" according to its 
  556. own base.  If you want to find out what the base is according to the 
  557. decimal numbering system, this will work: 
  558.  
  559. : decbase  ( -- )  base @ dup decimal .  base !  ;
  560.  
  561. Can you figure out why this works? 
  562.  
  563.  
  564. Arrays
  565. ======
  566.  
  567. Forth doesn't have very many explicit data structures, but it provides 
  568. good primitives for efficiently creating whatever kind of data 
  569. structures you want.  Let's build an array.  
  570.  
  571. We need to know a couple more words first.  
  572.  
  573. create  \ name ( -- adr )  defines a new word which will return its address
  574.                            when executed.  The name of the new word is taken
  575.                            from the input stream.
  576. allot  ( n -- )            allocates n bytes of storage for the most recently
  577.                            defined word.
  578.  
  579. CREATE is the like VARIABLE, except that variable automatically 
  580. allocates /N bytes of storage.  variable xxx is like the CREATE xxx 
  581. /cell allot).  Okay, here we go.  
  582.  
  583. : arrayvar  \ name  ( size-in-words -- )
  584.    cells create allot
  585. ;
  586. : a@  ( index adr -- value )  swap cells + @  ;
  587. : a!  ( value index adr -- )  swap cells + !  ;
  588.  
  589. ARRAYVAR will allow us to create an array to hold size words.  a@ and 
  590. a! will allow us to fetch and store elements of an array we have 
  591. created.  Let's make an array and initialise it to all zeroes.  
  592.  
  593. 50 arrayvar ourarray
  594. : init  ( n adr -- )  swap   0 do  0 over i a!  loop  ;
  595. 50 ourarray init
  596.  
  597.  
  598. Now let's put a 5 in the 23rd element.  
  599.  
  600. \d 5 23 ourarray a! 
  601.  
  602. Is it there? 
  603.  
  604. 23 ourarray a@  .
  605.  
  606. Of course it is.  Would I lie to you? Data structures in Forth can be 
  607. as sophisticated as you can imagine.  It's up to you; the primitives 
  608. are all present.  
  609.  
  610.  
  611. Vocabularies
  612. ============
  613.  
  614. Note: This section is incomplete.  The stuff that is here is correct, 
  615. but there are some words that I don't list.  Read the "Vocabularies 
  616. and Search Order" chapter in the manual for more information.  
  617.  
  618. Forth words may be grouped together in sets called VOCABULARIES .  
  619. This is somewhat analogous to directories in other operating systems, 
  620. whereby files are grouped together in different places.  
  621.  
  622. When Forth is looking for a word, it may search several vocabularies.  
  623. The vocabulary where Forth looks first is called the "context" 
  624. vocabulary, and there is a system variable called CONTEXT which keeps 
  625. track of which vocabulary is the "context".  All Forth systems have a 
  626. vocabulary whose name is FORTH. If the word that is sought is not 
  627. found in "context", a list of other vocabularies is searched.  
  628.  
  629. The "context" vocabulary specifies where to look for words.  It is 
  630. also necessary to know where to put the new words created by the user.  
  631. This vocabulary is called the "current" vocabulary (also known as the 
  632. "compilation vocabulary), and again there is a system word CURRENT to 
  633. keep track of which vocabulary is selected as the "current" one.  
  634.  
  635. Typical vocabularies present in most systems include FORTH, and 
  636. ASSEMBLER. Others may be present, and you can create your own if you 
  637. wish.  After you have created a vocabulary, you make make it the 
  638. "context" vocabulary by typing the vocabulary's name.  The only way to 
  639. make a vocabulary "current" is to first make it "context" (by typing 
  640. its name).  Then you may use the word "definitions" which sets the 
  641. "current" vocabulary to be the same as the "context" vocabulary.  
  642.  
  643. vocabulary  \ name ( -- )    creates a new vocabulary whose name is taken
  644.                              from the input stream.  Executing that
  645.                              name later will cause the new vocabulary
  646. definitions  ( -- )          makes the "CURRENT" vocabulary the same as
  647.                              "the "CONTEXT" one
  648. order  ( -- )                displays the list of vocabularies to be
  649.                              searched 
  650.  
  651.  
  652. So, if you want to make a new vocabulary named "myvoc", execute 
  653.  
  654. vocabulary myvoc
  655.  
  656. If you want your new vocabulary to be the one that is searched first 
  657. (i.e.  the "context"), just type its name.  
  658.  
  659. myvoc
  660.  
  661. If you wished new word definitions to go into your new vocabulary 
  662. (i.e.  make it "current"), all you have to do is type 
  663.  
  664. definitions
  665.  
  666. assuming that you have already made "myvoc" the "context" by typing 
  667. "myvoc".  If not, just execute 
  668.  
  669. myvoc definitions
  670.  
  671. It is possible to create vocabularies within vocabularies, but it is 
  672. most of the time you should create new vocabularies only within the 
  673. "forth" vocabulary.  To insure that this is the case, type 
  674.  
  675. forth definitions
  676.  
  677. before creating new vocabularies.  This way, you always know how to 
  678. find your vocabularies ( just type Forth then the vocabulary name).  
  679.  
  680.  
  681. Forgetting
  682. ==========
  683.  
  684. forget  \ name  ( -- )  forgets the named word from the dictionary.
  685.                         All words which have been defined after the
  686.                         named word are forgotten too.  This is necessary
  687.                         because the subsequent words may depend on the
  688.                         word you are forgetting.
  689. words  ( -- )           tells you what words the system knows
  690.  
  691.  
  692. Arithmetic Summary
  693. ==================
  694.  
  695. +  ( n1 n2 -- sum )           integer addition
  696. -  ( n1 n2 -- difference )    integer subtraction, n1-n2 
  697. 1+  ( n -- n+1 )              add 1.  This is provided as an alternative
  698.                               to "1 +" because it is such a frequent
  699.                               operation and should be optimized
  700. 1-  ( n -- n-1 )              subtract 1
  701. 2+  ( n -- n+2 )              add 2.
  702. 2-  ( n -- n-2 )              subtract 2
  703. *  ( n1 n2 -- product )       integer multiply
  704. 2*  ( n -- n*2 )              times 2.  Usually implemented by shifting
  705. /  ( n1 n2 -- quotient )      integer portion of quotient
  706. 2/  ( n -- n/2 )              halve.  Usually implemented by shifting
  707. mod  ( n1 n2 -- remainder )   integer remainder
  708. /mod  ( n1 n2 -- quotient remainder )
  709.                               quotient and remainder
  710. u*  ( un1 un2 -- ud )         like "*" but unsigned
  711. u/mod  ( u1 u2 -- uremainder uquotient )
  712.                               unsigned /mod
  713.  
  714. max  ( n1 n2 -- max )         maximum
  715. min  ( n1 n2 -- min )         minimum
  716. abs  ( n -- |n| )             absolute value 
  717. negate  ( n -- -n )           arithmetic negation 
  718. and  ( n1 n2 -- and )         bitwise logical and
  719. or  ( n1 n2 -- or )           bitwise logical or
  720. xor  ( n1 n2 -- xor )         bitwise logical exclusive-or
  721. not  ( n1 -- complement )     bitwise logical complement
  722.  
  723.  
  724. Further Topics and books
  725. ========================
  726.  
  727. There is a lot more to Forth than I have described here.  However, 
  728. this should be sufficient to get you a long way.  For a complete 
  729. introduction to the complete Forth language, I recommend the following 
  730. books: 
  731.  
  732. Mastering Forth
  733. Anita Anderson and Martin Tracy
  734. Mountain View Press,
  735. P.O. Box 4656,
  736. Mountain  View, CA 94040
  737.     
  738. Starting Forth
  739. Leo Brodie of Forth,Inc.
  740. Prentice-Hall,Inc.
  741. Englewood Cliffs, NJ 07632
  742.    
  743. Thinking Forth
  744. Leo Brodie
  745. Prentice-Hall,Inc.
  746.    
  747. Dr. Dobbs Toolbook of Forth, Parts I+II
  748.  
  749.